/*
 * Copyright (c) 2022 HiSilicon (Shanghai) Technologies CO., LIMITED.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <math.h>

#include "ohos_init.h"
#include "cmsis_os2.h"
#include "iot_i2c.h"
#include "iot_gpio.h"
#include "iot_errno.h"
#include "iot_adc.h"
#include "iot_gpio_ex.h"

#include "flower_data.h"
#include "oled_ssd1306.h"
#include "iot_config.h"

#define AHT20_BAUDRATE (400 * 1000)
#define AHT20_I2C_IDX 0

#define ADC_CHANNEL IOT_ADC_CHANNEL_2

#define MENU_WIFI   1
#define MENU_INFO   2
#define MENU_DETAIL 3

extern uint8_t Wifi_Connect_Flag;
extern uint8_t pump_state_flag;

unsigned char MenuState = MENU_WIFI;

unsigned short data;
uint8_t key_down = 0;                    // key down state
uint8_t key_up = 0;                     //key up stste
uint8_t key_long_down = 0;
uint8_t state_change_flag = 0;

/*
    温度
    PH值
    湿度
    花卉种类
*/
float temperature = 23.4;
float ph = 6.7;
float hum = 64.2;
uint8_t type = BUTTERFLY_ORCHID;


//定义状态变量
typedef enum{
    STATE_ADC_READ,         //初始态
    STATE_S1_DOWN,          //检测到S1按下
    STATE_S2_DOWN,          //检测到S2按下
    STATE_S1_LONG_UP,
    STATE_S2_LONG_UP,
    STATE_S1_UP,            //S1松开
    STATE_S2_UP,            //S1松开
}State_of_OledS;

static float GetVoltage(void)
{
    unsigned int ret;

    // 该函数通过使用AdcRead()函数来读取 ADC_CHANNEL_2 的数值存储在data中， 
    // WIFI_IOT_ADC_EQU_MODEL_8 表示8次平均算法模式，
    // WIFI_IOT_ADC_CUR_BAIS_DEFAULT 表示默认的自动识别模式，
    // 最后通过 data * 1.8 * 4 / 4096.0 计算出实际的电压值。
    ret = AdcRead(ADC_CHANNEL, &data, IOT_ADC_EQU_MODEL_8, IOT_ADC_CUR_BAIS_DEFAULT, 0xff);
    if (ret != IOT_SUCCESS)
    {
        printf("IOT_ADC_CHANNEL_5 Read Fail\n");
    }
/*
    else
    {
        printf("IOT_ADC_CHANNEL_5 Read Success\n");
    }
    */

//    return (float)data * 1.8 * 4 / 4096.0;
    return data;
}

static void OledDeviceInit(void)
{

    OledInit();
    OledFillScreen(0);
    IoTI2cInit(AHT20_I2C_IDX, AHT20_BAUDRATE);
}

//      欢迎使用
//    “护花使者”系统
static void WelcomePage(void)
{
    OledShowChinese(31,2,0);
    OledShowChinese(47,2,1);
    OledShowChinese(63,2,2);
    OledShowChinese(79,2,3);

    OledShowChinese(0,4,4);
    OledShowChinese(16,4,5);
    OledShowChinese(32,4,6);
    OledShowChinese(48,4,7);
    OledShowChinese(64,4,8);
    OledShowChinese(80,4,9);
    OledShowChinese(96,4,10);
    OledShowChinese(112,4,11);

}

static void Flower_name(uint8_t type)
{
    switch (type)
    {
        case MARIGOLD:
            OledShowChinese(48,2,48);   //金 1
            OledShowChinese(64,2,54);   //盏 1
            OledShowChinese(80,2,6);    //花
            OledShowChinese(96,2,13);   //空白 
            break;
        case AZALEA:
            OledShowChinese(48,2,51);   //杜 1
            OledShowChinese(64,2,52);   //鹃 1
            OledShowChinese(96,2,13);   //空白
            OledShowChinese(96,2,13);   //空白  
            break;
        case HYACINTH:
            OledShowChinese(48,2,27);   //风
            OledShowChinese(64,2,28);   //信
            OledShowChinese(80,2,26);   //子
            OledShowChinese(96,2,13);   //空白  
            break;
        case BUTTERFLY_ORCHID:
            OledShowChinese(48,2,31);   //蝴
            OledShowChinese(64,2,32);   //蝶
            OledShowChinese(80,2,24);   //兰
            OledShowChinese(96,2,13);   //空白  
            break;    
        case POINSETTIA:
            OledShowChinese(48,2,39);   //一
            OledShowChinese(64,2,33);   //品
            OledShowChinese(80,2,34);   //红
            OledShowChinese(96,2,13);   //空白  
            break;
        case UNKNOWN:
            OledShowChinese(48,2,40);   //未
            OledShowChinese(64,2,41);   //知
            OledShowChinese(80,2,6);    //花
            OledShowChinese(96,2,42);   //卉  
            break;                             
        default:
            OledShowChinese(48,2,40);   //未
            OledShowChinese(64,2,41);   //知
            OledShowChinese(80,2,6);    //花
            OledShowChinese(96,2,42);   //卉  
            break;
    }
}

static void Flower_Data_Dis(uint8_t type,float temperature,float ph,float hum)
{
    uint8_t c;
    Flower_name(type);

    OledShowDecimal(48,5,temperature,2,1,FONT6_X8);
    OledShowString(72,5,(uint8_t*)"'C",FONT6_X8);

    OledShowDecimal(48,6,ph,2,1,FONT6_X8);

    OledShowDecimal(48,7,hum,2,1,FONT6_X8);
    OledShowString(72,7,(uint8_t*)"%",FONT6_X8);

    if(type == UNKNOWN)
    {
        OledShowString(120,5," ",FONT6_X8);
        OledShowString(120,6," ",FONT6_X8);
        OledShowString(120,7," ",FONT6_X8); 
    }
    else
    {
        c = temp_func(type,temperature);
        if(c == 'l')
            OledShowString(120,5,"l",FONT6_X8);
        else if(c == 'h')
            OledShowString(120,5,"h",FONT6_X8);
        else if(c == 'r')
            OledShowString(120,5,"r",FONT6_X8);
        else
            OledShowString(120,5," ",FONT6_X8);

        c = ph_func(type,ph);
        if(c == 'l')
            OledShowString(120,6,"l",FONT6_X8);
        else if(c == 'h')
            OledShowString(120,6,"h",FONT6_X8);
        else if(c == 'r')
            OledShowString(120,6,"r",FONT6_X8);
        else
            OledShowString(120,6," ",FONT6_X8);

        c = hum_func(type,hum);
        if(c == 'l')
            OledShowString(120,7,"l",FONT6_X8);
        else if(c == 'h')
            OledShowString(120,7,"h",FONT6_X8);
        else if(c == 'r')
            OledShowString(120,7,"r",FONT6_X8);
        else
            OledShowString(120,7," ",FONT6_X8);  
    } 
}

static void InfoDis(void)
{
    OledShowString(0,2,(uint8_t*)"Type:",FONT8_X16);
    OledShowString(0,5,(uint8_t*)"Temp: ",FONT6_X8);
    OledShowString(0,6,(uint8_t*)"PH  : ",FONT6_X8);
    OledShowString(0,7,(uint8_t*)"Hum : ",FONT6_X8);
 
    Flower_Data_Dis(type,temperature,ph,hum);

    if(pump_state_flag) 
        OledShowChinese(111,0,12);
    else
        OledShowChinese(111,0,13);
}

static void WifiStateDis(void)
{
    static uint8_t Last_Flag;

    if(Last_Flag != Wifi_Connect_Flag)
    {
        OledFillScreen(0);
    }
    Last_Flag = Wifi_Connect_Flag;  
    switch (Wifi_Connect_Flag)
    {
        case 0:
            OledShowString(0,2,(uint8_t*)"   Wifi  Wait",FONT6_X8);
            OledShowString(0,4,(uint8_t*)"   to Connect",FONT6_X8);
 //           OledShowString(88,6,CONFIG_AP_SSID,FONT6_X8);
            break;
        case 1:
            OledShowString(0,2,(uint8_t*)"Wifi   Connected",FONT8_X16);
            OledShowString(40,6,(uint8_t*)"SSID: ",FONT6_X8);
            OledShowString(88,6,CONFIG_AP_SSID,FONT6_X8);

            break;
        case 2:
            OledShowString(0,2,(uint8_t*)"Wifi Disconected",FONT8_X16);
            OledShowString(40,6,(uint8_t*)"SSID: ",FONT6_X8);
            OledShowString(88,6,CONFIG_AP_SSID,FONT6_X8);
            break;  
        default:
            break;
    }  
}

static void DetailDis(void)
{
    uint8_t c;

    if(type == UNKNOWN)
    {
        OledShowString(0,2,"Unkonwn Info ",FONT6_X8);
        OledShowString(0,4,"Unkonwn Info ",FONT6_X8);
        OledShowString(0,6,"Unkonwn Info ",FONT6_X8);
        OledShowString(0,3,"                    ",FONT6_X8);
        OledShowString(0,5,"                    ",FONT6_X8);
        OledShowString(0,7,"                    ",FONT6_X8);
    }
    else
    {
        c = temp_func(type,temperature);
        if(c == 'l')
            OledShowString(0,2,"Low temp     ",FONT6_X8);
        else if(c == 'h')
            OledShowString(0,2,"High temp    ",FONT6_X8);
        else if(c == 'r')
            OledShowString(0,2,"Moderate temp",FONT6_X8);
        else
            OledShowString(0,2,"             ",FONT6_X8);

        OledShowString(0 ,3,"tem:",FONT6_X8);
        OledShowString(60,3,"`C",FONT6_X8);
        OledShowString(110,3,"`C",FONT6_X8);
        OledShowString(76,3,"-",FONT6_X8),
        OledShowDecimal(36,3,temp_mim(type),2,1,FONT6_X8);
        OledShowDecimal(86,3,temp_max(type),2,1,FONT6_X8);

        c = ph_func(type,ph);
        if(c == 'l')
            OledShowString(0,4,"Low  pH    ",FONT6_X8);
        else if(c == 'h')
            OledShowString(0,4,"High pH    ",FONT6_X8);
        else if(c == 'r')
            OledShowString(0,4,"Moderate pH",FONT6_X8);
        else
            OledShowString(0,4,"            ",FONT6_X8);
        OledShowString(0 ,5,"pH:",FONT6_X8);
        OledShowString(68,5,"-",FONT6_X8),
        OledShowDecimal(36,5,ph_mim(type),2,1,FONT6_X8);
        OledShowDecimal(86,5,ph_max(type),2,1,FONT6_X8);

        c = hum_func(type,hum);
        if(c == 'l')
            OledShowString(0,6,"Low hum     ",FONT6_X8);
        else if(c == 'h')
            OledShowString(0,6,"High hum    ",FONT6_X8);
        else if(c == 'r')
            OledShowString(0,6,"Moderate hum",FONT6_X8);
        else
            OledShowString(0,6,"            ",FONT6_X8);  
        OledShowString(0 ,7,"hum:",FONT6_X8);
        OledShowString(72,7,"-",FONT6_X8),
        OledShowString(60 ,7,"%",FONT6_X8);
        OledShowString(110 ,7,"%",FONT6_X8);
        OledShowDecimal(36,7,hum_mim(type),2,1,FONT6_X8);
        OledShowDecimal(86,7,hum_max(type),2,1,FONT6_X8); 
    }           
}

static void OledSwitchTask(void)
{
    unsigned short S_Value;
    uint8_t LastState = 0;
    uint16_t LongDownTime = 0;

    State_of_OledS state;               //初始化状态
    while (1)
    {   
        // 获取电压值
        S_Value = GetVoltage();         //读取GPIO5 ADC 值
        switch(state)
        {
            case STATE_ADC_READ:{
                key_down = 0;
                key_up = 0;
                if (S_Value < 450 && S_Value >250){
                    state = STATE_S1_DOWN;                      //检测到S1按下 跳转到 STATE_S1_DOWN 状态
                }
                else if (S_Value > 451 && S_Value < 600){
                    state = STATE_S2_DOWN;                      //检测到S2按下 跳转到 STATE_S2_DOWN 状态
                } 
                else{
                    state = STATE_ADC_READ;                     //按键未按下时 进行循环读取
                }
                break;
            }
            case STATE_S1_DOWN:{                                //检测到按键松开 跳转到 STATE_S1_UP， 否则 状态 STATE_S1_DOWN 中循环 直到洞开
                key_down = 1;
                if(S_Value < 450 && S_Value > 250){
                    LongDownTime ++;
                    state = STATE_S1_DOWN;
                }
                else{   
                    if(LongDownTime > 100){
                        LongDownTime = 0;
                        state = STATE_S1_LONG_UP;
                    }
                    else{
                        LongDownTime = 0;
                        state = STATE_S1_UP;
                    }
                }
                break;
            }
            case STATE_S2_DOWN:{
                key_down = 2;
                if(S_Value < 600 && S_Value > 250){
                    LongDownTime ++;
                    state = STATE_S2_DOWN;
                }
                else{   
                    if(LongDownTime > 100){
                        LongDownTime = 0;
                        state = STATE_S2_LONG_UP;
                    }
                    else{
                        LongDownTime = 0;
                        state = STATE_S2_UP;
                    }
                }
                break;
            }
            case STATE_S1_UP:{                                  //打印相关按键信息 返回 初始态
                /*按键状态变量待添加*/
                key_up = 1;
                MenuState = MENU_WIFI;

                if(LastState != MenuState)
                    state_change_flag = 1;
                else
                    state_change_flag = 0;

                state = STATE_ADC_READ;

                break;
            }
            case STATE_S2_UP:{
                /*按键状态变量待添加*/
                key_up = 2;
                MenuState = MENU_INFO;

                if(LastState != MenuState)
                    state_change_flag = 1;
                else
                    state_change_flag = 0;

                state = STATE_ADC_READ;
                break;
            }
            case STATE_S1_LONG_UP:{                                  //打印相关按键信息 返回 初始态
                /*按键状态变量待添加*/
                key_long_down = 1;

                if(LastState != MenuState)
                    state_change_flag = 1;
                else
                    state_change_flag = 0;

                state = STATE_ADC_READ;

                break;
            }
            case STATE_S2_LONG_UP:{
                /*按键状态变量待添加*/
                key_long_down = 2;
                MenuState = MENU_DETAIL;
                if(LastState != MenuState)
                    state_change_flag = 1;
                else
                    state_change_flag = 0;

                state = STATE_ADC_READ;
                break;
            }
            default:{
                state = STATE_ADC_READ;
                break;
            }
            LastState = MenuState;
        }
        //延时10ms
        TaskMsleep(10);
    }
}

static void OledDataTask(const char *arg)
{
    uint8_t LastState = 0;

    OledDeviceInit();
    TaskMsleep(500);

    OledFillScreen(0);
    TaskMsleep(10);
    WelcomePage();

    TaskMsleep(5000);
    OledFillScreen(0);

    while (1)
    {
        if(state_change_flag)
        {
            OledFillScreen(0);
            state_change_flag = 0;
        }
        if(MenuState == MENU_WIFI)
        {
            WifiStateDis();
        }
        if(MenuState == MENU_INFO)
        {
            InfoDis();
        }
        if(MenuState == MENU_DETAIL)
        {
            DetailDis();
        }
        TaskMsleep(50);
    }

}

#define OLEDDIS_TASK_STACK_SIZE 1024 * 8
#define OLEDDIS_TASK_PRIO 24
#define SWITCH_TASK_STACK_SIZE 1024 * 8
#define SWITCH_TASK_PRIO 25

static void OledSwitchEntry(void)
{
    osThreadAttr_t attr;

    attr.name = "OledSwitchTask";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = SWITCH_TASK_STACK_SIZE;
    attr.priority = SWITCH_TASK_PRIO;

    if (osThreadNew((osThreadFunc_t)OledSwitchTask, NULL, &attr) == NULL)
    {
        printf("[OledSwitch] Falied to create OledSwitch!\n");
    }
    else{
        printf("[OledSwitch] Successed to create OledSwitch in priority:%d!\n",SWITCH_TASK_PRIO);
    }
}

static void OledDataEntry(void)
{
    osThreadAttr_t attr;
    attr.name = "OledDataTask";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = OLEDDIS_TASK_STACK_SIZE; /* 任务大小5120 */
    attr.priority = OLEDDIS_TASK_PRIO;

    if (osThreadNew(OledDataTask, NULL, &attr) == NULL) {
        printf("[OledData] Falied to create OledDataTask!\n");
    }
    else{
        printf("[OledData] Successed to create OledDataTask in priority:%d!\n",OLEDDIS_TASK_PRIO);
    }
}

APP_FEATURE_INIT(OledSwitchEntry);
APP_FEATURE_INIT(OledDataEntry);